package com.dcdata.haixin.handler;

import com.alibaba.fastjson.JSON;
import com.dcdata.haixin.bean.*;
import com.dcdata.haixin.common.CommonUtils;
import com.dcdata.haixin.common.FileUtils;
import com.dcdata.haixin.enums.body.ShakeHandItem;
import com.dcdata.haixin.enums.head.HeadItemIndex;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.java.Log;

import java.io.IOException;

/**
 * @author: xinmi
 * @date: 2020/11/26
 * @description:
 */
@Log
@Sharable
public class MessageHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Message message = (Message)msg;

        byte packageType = message.getPackageType();

        switch(packageType){
            case 0x01:
                handleLogin(message, ctx);
                break;
            case 0x03:
                handleGps(message, ctx);
                break;
            case 0x4:
                handleDaoLi(message, ctx);
                break;
            case 0x08:
                handleShakeHand(message, ctx);
                break;
        }

        //log.info(JSON.toJSON(message).toString());

    }

    public void handleLogin(Message message, ChannelHandlerContext ctx){
        MessageRespone messageRespone = new MessageRespone();
        int totalLength = message.getTotalLengh();
        messageRespone.setTotalLengh(totalLength);
        messageRespone.setPackageType(message.getPackageType());
        int headLength = message.getHeadLengh();
        messageRespone.setHeadLengh(headLength);
        int bodyLength = totalLength - headLength - 8;

        ByteBuf headBuf = PooledByteBufAllocator.DEFAULT.buffer(headLength);

        for (HeadItem headItem: message.getHead().getHeadItemList()) {
            switch (headItem.getHeadItemIndex()){
                case SOURCE_ADDRESS_ORGNIZATION:
                    headBuf.writeByte(0x01);
                    break;
                case SOURCE_TYPE:
                    headBuf.writeByte(0x02);
                    break;
                case SOURCE_ADDRESS:
                    headBuf.writeByte(0x03);
                    break;
                case DESTINATION_TYPE:
                    headBuf.writeByte(0x04);
                    break;
                case DESTINATION_ADDRESS:
                    headBuf.writeByte(0x05);
                    break;
                case RESPONE_FIELD:
                    headBuf.writeByte(0x06);
                    break;
                case PRIORITY:
                    headBuf.writeByte(0x07);
                    break;
                case SEQUENCE:
                    headBuf.writeByte(0x08);
                    break;
                case TIMESTAMP:
                    headBuf.writeByte(0x09);
                    break;
                case END_FLAG:
                    headBuf.writeByte(0x0a);
                    break;
            }

            switch (headItem.getDataType()){
                case UINT32:
                    headBuf.writeByte(0x01);
                    headBuf.writeBytes(headItem.getValue());
                    break;
                case UNIT16:
                    headBuf.writeByte(0x02);
                    headBuf.writeBytes(headItem.getValue());
                    break;
                case BYTE:
                    headBuf.writeByte(0x03);
                    if (headItem.getValue()[0] == 0x02 && headItem.getHeadItemIndex() == HeadItemIndex.RESPONE_FIELD ){
                        byte[] bytes = new byte[1];
                        bytes[0] = 0x03;
                        headBuf.writeBytes(bytes);    
                    }

                    break;
                case COMPOSITE:
                    headBuf.writeByte(0x04);
                    headBuf.writeBytes(headItem.getValue());
                    break;
                case BIGBUF:
                    headBuf.writeByte(0x05);
                    headBuf.writeBytes(headItem.getValue());
                    break;
            }

        }

        ByteBuf bodyBuf = PooledByteBufAllocator.DEFAULT.buffer(bodyLength);

        for (LoginItem loginItem: message.getBody().getLoginItemList()) {
            if (loginItem.getLoginItemIndex() != null) {
                switch (loginItem.getLoginItemIndex()) {
                    case USER_TYPE:
                        bodyBuf.writeByte(0x01);
                        break;
                    case USER_ID:
                        bodyBuf.writeByte(0x02);
                        break;
                    case LOGIN_REASON:
                        bodyBuf.writeByte(0x03);
                        break;
                    case SHAKEHAND_PERIOD:
                        bodyBuf.writeByte(0x04);
                        break;
                }
            }
            if (loginItem.getDataType() != null) {
                switch (loginItem.getDataType()) {
                    case UINT32:
                        bodyBuf.writeByte(0x01);
                        bodyBuf.writeBytes(loginItem.getValue());
                        break;
                    case UNIT16:
                        bodyBuf.writeByte(0x02);
                        bodyBuf.writeBytes(loginItem.getValue());
                        break;
                    case BYTE:
                        bodyBuf.writeByte(0x03);
                        bodyBuf.writeBytes(loginItem.getValue());
                        break;
                    case COMPOSITE:
                        bodyBuf.writeByte(0x04);
                        bodyBuf.writeBytes(loginItem.getValue());
                        break;
                    case BIGBUF:
                        bodyBuf.writeByte(0x05);
                        bodyBuf.writeBytes(loginItem.getValue());
                        break;
                }
            }
        }

        ctx.channel().writeAndFlush(messageRespone);
    }

    public void handleGps(Message message, ChannelHandlerContext ctx) throws IOException {
        GpsData gpsData = new GpsData();

        int longitude_high = 0;
        int longitude_low = 0;
        int latitude_high = 0;
        int latitude_low = 0;

        for (GpsItem gpsItem: message.getBody().getGpsItemList()) {

            if (gpsItem.getGpsItemIndex() != null) {
                switch (gpsItem.getGpsItemIndex()) {
                    case LONGITUDE_HIGH:
                        longitude_high = CommonUtils.bytes2int(gpsItem.getValue());
                        break;
                    case LONGITUDE_LOW:
                        longitude_low = CommonUtils.bytes2int(gpsItem.getValue());
                        break;
                    case LATITUDE_HIGH:
                        latitude_high = CommonUtils.bytes2int(gpsItem.getValue());
                        break;
                    case LATITUDE_LOW:
                        latitude_low = CommonUtils.bytes2int(gpsItem.getValue());
                        break;
                    case HEIGHT:
                        gpsData.setHeight(CommonUtils.bytes2Short(gpsItem.getValue()));
                        break;
                    case INSTANT_SPEED:
                        gpsData.setSpeed(CommonUtils.bytes2Short(gpsItem.getValue()));
                        break;
                    case DIRECTION_ANGLE:
                        gpsData.setDirectionAngle(CommonUtils.bytes2Short(gpsItem.getValue()));
                        break;
                    case TIME:
                        gpsData.setTime(CommonUtils.bytes2int(gpsItem.getValue()));
                        break;
                    case TIME_TYPE:
                        gpsData.setTimeType(gpsItem.getValue()[0]);
                        break;
                    case REPLACEMENT_SIGNS:
                        gpsData.setReplacementSigns(gpsItem.getValue()[0]);
                        break;
                    case AVERAGE_VELOCITY:
                        gpsData.setAverageVelocity(CommonUtils.bytes2Short(gpsItem.getValue()));
                        break;
                    case TYPE_OF_TRAIN:
                        gpsData.setTypeTrain(gpsItem.getValue()[0]);
                        break;
                    case SUBLINE_NUMBER:
                        gpsData.setSublineNumber(CommonUtils.bytes2int(gpsItem.getValue()));
                        break;
                    case SITE_UNIFORM_NUMBER:
                        gpsData.setSiteUniformNumber(CommonUtils.bytes2int(gpsItem.getValue()));
                        break;
                    case TYPE_OF_TRAIN_FLAG:
                        gpsData.setTypeTranFlag(gpsItem.getValue()[0]);
                        break;
                    case VEHICLE_TURN_AROUND:
                        gpsData.setVehicleTurnAround(gpsItem.getValue()[0]);
                        break;
                    case CUMULATIVE_MILEAGE:
                        gpsData.setCumulativeMileage(CommonUtils.bytes2int(gpsItem.getValue()));
                        break;
                    case CUMULATIVE_MILEAGE_SENSOR:
                        gpsData.setCumulativeMileageSensor(CommonUtils.bytes2int(gpsItem.getValue()));
                        break;
                    case RESIDUAL_OIL:
                        gpsData.setResidualOil(CommonUtils.bytes2int(gpsItem.getValue()));
                        break;
                    case AIR_CONDITION:
                        gpsData.setAirCondition(gpsItem.getValue()[0]);
                        break;
                    case LOCATION_INFORMATION_SET:
                        gpsData.setLocationInformationSet(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD1:
                        gpsData.setExtensionField1(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD2:
                        gpsData.setExtensionField2(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD3:
                        gpsData.setExtensionField3(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD4:
                        gpsData.setExtensionField4(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD5:
                        gpsData.setExtensionField5(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD6:
                        gpsData.setExtensionField6(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD7:
                        gpsData.setExtensionField7(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD8:
                        gpsData.setExtensionField8(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD9:
                        gpsData.setExtensionField9(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD10:
                        gpsData.setExtensionField10(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD11:
                        gpsData.setExtensionField11(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD12:
                        gpsData.setExtensionField12(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD13:
                        gpsData.setExtensionField13(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD14:
                        gpsData.setExtensionField14(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD15:
                        gpsData.setExtensionField15(gpsItem.getValue());
                        break;
                    case EXTENSION_FIELD16:
                        gpsData.setExtensionField16(gpsItem.getValue());
                        break;
                    case RESERVATION:
                        gpsData.setReservation(gpsItem.getValue()[0]);
                        break;
                    case RESERVATION1:
                        gpsData.setReservation1(gpsItem.getValue()[0]);
                        break;
                    case RESERVATION2:
                        gpsData.setReservation2(CommonUtils.bytes2int(gpsItem.getValue()));
                        break;
                    case SITE_NUMBER:
                        gpsData.setSiteNumber(CommonUtils.bytes2int(gpsItem.getValue()));
                        break;
                    case VEHICLE_STATUS_POSITION:
                        gpsData.setVehicleStatusPosition(CommonUtils.bytes2int(gpsItem.getValue()));
                        break;
                    case GPS_STATUS:
                        gpsData.setGpsStatus(gpsItem.getValue()[0]);
                        break;
                    case AUXILIARY_DATA1:
                        gpsData.setAuxiliaryData1(gpsItem.getValue()[0]);
                        break;
                    case AUXILIARY_DATA2:
                        gpsData.setAuxiliaryData2(gpsItem.getValue()[0]);
                        break;
                    case AUXILIARY_DATA3:
                        gpsData.setAuxiliaryData3(gpsItem.getValue());
                        break;
                    case AUXILIARY_DATA4:
                        gpsData.setAuxiliaryData4(gpsItem.getValue());
                        break;
                    case AUXILIARY_DATA5:
                        gpsData.setAuxiliaryData5(gpsItem.getValue());
                        break;
                }
            }
        }
        String longitudeStr = longitude_high + "." + longitude_low;
        String latitudeStr = latitude_high + "." + latitude_low;

        gpsData.setLongitude(Double.parseDouble(longitudeStr.replace("-", "")));
        gpsData.setLatitude(Double.parseDouble(latitudeStr.replace("-", "")));

        FileUtils.WriteWithFileName(FileUtils.getGpsFileName(),JSON.toJSON(gpsData).toString());

    }

    public void handleDaoLi(Message message, ChannelHandlerContext ctx) throws IOException {
        DaoLiData daoLiData = new DaoLiData();

        for (DaoLiItem daoLiItem: message.getBody().getDaoLiItemList()) {
            if(daoLiItem.getDaoLiItemIndex() != null) {
                switch (daoLiItem.getDaoLiItemIndex()) {
                    case ARRIVAL_SIGNS:
                        daoLiData.setArrivalSigns(daoLiItem.getValue()[0]);
                        break;
                    case SITE_NUMBER:
                        daoLiData.setSiteNumber(CommonUtils.bytes2int(daoLiItem.getValue()));
                        break;
                    case SUB_ROUTE_NUMBER:
                        daoLiData.setSubRouteNumber(CommonUtils.bytes2int(daoLiItem.getValue()));
                        break;
                    case SITE_PROPERTIES:
                        daoLiData.setSiteProperties(daoLiItem.getValue()[0]);
                        break;
                    case AUTOMATIC_MANUAL_MARKING:
                        daoLiData.setAutomaticManualMarking(daoLiItem.getValue()[0]);
                        break;
                    case ARRIVAL_TIME:
                        daoLiData.setArrivalTime(CommonUtils.bytes2int(daoLiItem.getValue()));
                        break;
                    case TIME_TYPE:
                        daoLiData.setTimeType(daoLiItem.getValue()[0]);
                        break;
                    case LINE_TYPE:
                        daoLiData.setLineType(daoLiItem.getValue()[0]);
                        break;
                    case LINE_SEGMENT_NUMBER:
                        daoLiData.setLineSegmentNumber(CommonUtils.bytes2int(daoLiItem.getValue()));
                        break;
                    case REPLACEMENT_SIGNS:
                        daoLiData.setReplacementSigns(daoLiItem.getValue()[0]);
                        break;
                    case SECOND_STATION_SIGN:
                        daoLiData.setSecondStationSign(daoLiItem.getValue()[0]);
                        break;
                    case SITE_NUMBER_FOR_NEXT_STOP:
                        daoLiData.setSiteNumberForNextStop(daoLiItem.getValue()[0]);
                        break;
                    case LONGITUDE_HIGH:
                        daoLiData.setLongitudeHigh(CommonUtils.bytes2Short(daoLiItem.getValue()));
                        break;
                    case LONGITUDE_LOW:
                        daoLiData.setLongitudeLow(CommonUtils.bytes2int(daoLiItem.getValue()));
                        break;
                    case LATITUDE_HIGH:
                        daoLiData.setLatitudeHigh(CommonUtils.bytes2Short(daoLiItem.getValue()));
                        break;
                    case LATITUDE_LOW:
                        daoLiData.setLatitudeLow(CommonUtils.bytes2int(daoLiItem.getValue()));
                        break;
                    case HEIGHT:
                        daoLiData.setHeight(CommonUtils.bytes2Short(daoLiItem.getValue()));
                        break;
                    case INSTANT_SPEED:
                        daoLiData.setInstantSpeed(CommonUtils.bytes2Short(daoLiItem.getValue()));
                        break;
                    case DIRECTION_ANGLE:
                        daoLiData.setDirectionAngle(CommonUtils.bytes2Short(daoLiItem.getValue()));
                        break;
                    case AVERAGE_VELOCITY:
                        daoLiData.setAverageVelocity(CommonUtils.bytes2Short(daoLiItem.getValue()));
                        break;
                    case SITE_UNIFORM_NUMBER:
                        daoLiData.setSiteUniformNumber(CommonUtils.bytes2int(daoLiItem.getValue()));
                        break;
                    case TYPE_OF_TRAIN:
                        daoLiData.setTypeOfTrain(daoLiItem.getValue()[0]);
                        break;
                    case TYPE_OF_TRAIN_FLAG:
                        daoLiData.setTypeOfTrainFlag(daoLiItem.getValue()[0]);
                        break;
                    case CUMULATIVE_MILEAGE:
                        daoLiData.setCumulativeMileage(CommonUtils.bytes2int(daoLiItem.getValue()));
                        break;
                    case VEHICLE_COMMUNICATION_NUMBER:
                        daoLiData.setVehicleCommunicationNumber(CommonUtils.bytes2int(daoLiItem.getValue()));
                        break;
                    case LOCATION_INFORMATION_SET:
                        daoLiData.setLocationInformationSet(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD1:
                        daoLiData.setExtensionField1(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD2:
                        daoLiData.setExtensionField2(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD3:
                        daoLiData.setExtensionField3(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD4:
                        daoLiData.setExtensionField4(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD5:
                        daoLiData.setExtensionField5(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD6:
                        daoLiData.setExtensionField6(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD7:
                        daoLiData.setExtensionField7(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD8:
                        daoLiData.setExtensionField8(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD9:
                        daoLiData.setExtensionField9(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD10:
                        daoLiData.setExtensionField10(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD11:
                        daoLiData.setExtensionField11(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD12:
                        daoLiData.setExtensionField12(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD13:
                        daoLiData.setExtensionField13(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD14:
                        daoLiData.setExtensionField14(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD15:
                        daoLiData.setExtensionField15(daoLiItem.getValue());
                        break;
                    case EXTENSION_FIELD16:
                        daoLiData.setExtensionField16(daoLiItem.getValue());
                        break;
                    case RESERVATION:
                        daoLiData.setReservation(daoLiItem.getValue()[0]);
                        break;
                    case RESERVATION1:
                        daoLiData.setReservation1(daoLiItem.getValue()[0]);
                        break;
                    case RESERVATION2:
                        daoLiData.setReservation2(daoLiItem.getValue()[0]);
                        break;
                    case CUMULATIVE_MILEAGE_SENSOR:
                        daoLiData.setCumulativeMileageSensor(CommonUtils.bytes2int(daoLiItem.getValue()));
                        break;
                }
            }
        }
        FileUtils.WriteWithFileName(FileUtils.getDaoLiFileName(),JSON.toJSON(daoLiData).toString());

    }

    public void handleShakeHand(Message message, ChannelHandlerContext ctx){
        MessageRespone messageRespone = new MessageRespone();
        int totalLength = message.getTotalLengh();
        messageRespone.setTotalLengh(totalLength);
        messageRespone.setPackageType(message.getPackageType());
        int headLength = message.getHeadLengh();
        messageRespone.setHeadLengh(headLength);
        int bodyLength = totalLength - headLength - 8;

        ByteBuf headBuf = PooledByteBufAllocator.DEFAULT.buffer(headLength);

        for (HeadItem headItem: message.getHead().getHeadItemList()) {
            switch (headItem.getHeadItemIndex()){
                case SOURCE_ADDRESS_ORGNIZATION:
                    headBuf.writeByte(0x01);
                    break;
                case SOURCE_TYPE:
                    headBuf.writeByte(0x02);
                    break;
                case SOURCE_ADDRESS:
                    headBuf.writeByte(0x03);
                    break;
                case DESTINATION_TYPE:
                    headBuf.writeByte(0x04);
                    break;
                case DESTINATION_ADDRESS:
                    headBuf.writeByte(0x05);
                    break;
                case RESPONE_FIELD:
                    headBuf.writeByte(0x06);
                    break;
                case PRIORITY:
                    headBuf.writeByte(0x07);
                    break;
                case SEQUENCE:
                    headBuf.writeByte(0x08);
                    break;
                case TIMESTAMP:
                    headBuf.writeByte(0x09);
                    break;
                case END_FLAG:
                    headBuf.writeByte(0x0a);
                    break;
            }

            switch (headItem.getDataType()){
                case UINT32:
                    headBuf.writeByte(0x01);
                    headBuf.writeBytes(headItem.getValue());
                    break;
                case UNIT16:
                    headBuf.writeByte(0x02);
                    headBuf.writeBytes(headItem.getValue());
                    break;
                case BYTE:
                    headBuf.writeByte(0x03);
                    headBuf.writeBytes(headItem.getValue());
                    break;
                case COMPOSITE:
                    headBuf.writeByte(0x04);
                    headBuf.writeBytes(headItem.getValue());
                    break;
                case BIGBUF:
                    headBuf.writeByte(0x05);
                    headBuf.writeBytes(headItem.getValue());
                    break;
            }

        }

        ByteBuf bodyBuf = PooledByteBufAllocator.DEFAULT.buffer(bodyLength);

        for (ShakeHandItem shakeHandItem: message.getBody().getShakeHandItemList()) {
            bodyBuf.writeByte(0x01);

            switch (shakeHandItem.getDataType()) {
                case UINT32:
                    bodyBuf.writeByte(0x01);
                    bodyBuf.writeByte(shakeHandItem.getValue());
                    break;
                case UNIT16:
                    bodyBuf.writeByte(0x02);
                    bodyBuf.writeByte(shakeHandItem.getValue());
                    break;
                case BYTE:
                    bodyBuf.writeByte(0x03);
                    bodyBuf.writeByte(shakeHandItem.getValue());
                    break;
                case COMPOSITE:
                    bodyBuf.writeByte(0x04);
                    bodyBuf.writeByte(shakeHandItem.getValue());
                    break;
                case BIGBUF:
                    bodyBuf.writeByte(0x05);
                    bodyBuf.writeByte(shakeHandItem.getValue());
                    break;
            }
        }
        ctx.channel().writeAndFlush(messageRespone);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
